// /import editor.js
// /import core/browser.js
// /import core/dom/dom.js
// /import core/dom/dtd.js
// /import core/dom/domUtils.js
// /import core/dom/Range.js
/**
 * @class baidu.editor.dom.Selection Selection类
 */
baidu.editor.dom.Selection = baidu.editor.dom.Selection || {};
(function() {
	baidu.editor.dom.Selection = Selection;

	var domUtils = baidu.editor.dom.domUtils, dtd = baidu.editor.dom.dtd, ie = baidu.editor.browser.ie;

	function getBoundaryInformation(range, start) {

		var getIndex = domUtils.getNodeIndex;

		range = range.duplicate();
		range.collapse(start);

		var parent = range.parentElement();

		// 如果节点里没有子节点，直接退出
		if (!parent.hasChildNodes()) {
			return {
				container : parent,
				offset : 0
			};
		}

		var siblings = parent.children, child, testRange = range.duplicate(), startIndex = 0, endIndex = siblings.length
				- 1, index = -1, distance;

		while (startIndex <= endIndex) {
			index = Math.floor((startIndex + endIndex) / 2);
			child = siblings[index];
			testRange.moveToElementText(child);
			var position = testRange.compareEndPoints('StartToStart', range);

			if (position > 0) {

				endIndex = index - 1;
			} else if (position < 0) {

				startIndex = index + 1;
			} else {
				// trace:1043
				return {
					container : parent,
					offset : getIndex(child)
				};
				// return dtd.$empty[child.tagName.toLowerCase()] ?
				// {container:parent,offset:getIndex( child )} :
				// {container:child,offset:0}

			}
		}

		if (index == -1) {
			testRange.moveToElementText(parent);
			testRange.setEndPoint('StartToStart', range);
			distance = testRange.text.replace(/(\r\n|\r)/g, '\n').length;
			siblings = parent.childNodes;
			if (!distance) {
				child = siblings[siblings.length - 1];
				return {
					container : child,
					offset : child.nodeValue.length
				};
			}

			var i = siblings.length;
			while (distance > 0)
				distance -= siblings[--i].nodeValue.length;

			return {
				container : siblings[i],
				offset : -distance
			}
		}

		testRange.collapse(position > 0);
		testRange.setEndPoint(position > 0 ? 'StartToStart' : 'EndToStart',
				range);
		distance = testRange.text.replace(/(\r\n|\r)/g, '\n').length;
		if (!distance) {
			return dtd.$empty[child.tagName] || dtd.$nonChild[child.tagName] ?

			{
				container : parent,
				offset : getIndex(child) + (position > 0 ? 0 : 1)
			} : {
				container : child,
				offset : position > 0 ? 0 : child.childNodes.length
			}
		}

		while (distance > 0) {
			try {
				var pre = child;
				child = child[position > 0 ? 'previousSibling' : 'nextSibling'];
				distance -= child.nodeValue.length;
			} catch (e) {
				return {
					container : parent,
					offset : getIndex(pre)
				};
			}

		}
		return {
			container : child,
			offset : position > 0 ? -distance : child.nodeValue.length
					+ distance
		}
	}

	/**
	 * 将ieRange转换为Range对象
	 * 
	 * @param {Range}
	 *            ieRange ieRange对象
	 * @param {Range}
	 *            range Range对象
	 * @return {Range} range 返回转换后的Range对象
	 */
	function transformIERangeToRange(ieRange, range) {
		if (ieRange.item) {
			range.selectNode(ieRange.item(0));
		} else {
			var bi = getBoundaryInformation(ieRange, true);
			range.setStart(bi.container, bi.offset);
			if (ieRange.compareEndPoints('StartToEnd', ieRange) != 0) {
				bi = getBoundaryInformation(ieRange, false);
				range.setEnd(bi.container, bi.offset);
			}
		}
		return range;
	}

	/**
	 * 获得ieRange
	 * 
	 * @param {Selection}
	 *            sel Selection对象
	 * @return {ieRange} 得到ieRange
	 */
	function _getIERange(sel) {
		var ieRange = sel.getNative().createRange();
		var el = ieRange.item ? ieRange.item(0) : ieRange.parentElement();
		if ((el.ownerDocument || el) === sel.document) {
			return ieRange;
		}
		return null;
	}
	function Selection(doc) {
		var me = this, iframe;
		me.document = doc;

		if (ie) {
			iframe = domUtils.getWindow(doc).frameElement;
			domUtils.on(iframe, 'beforedeactivate', function() {

						me._bakIERange = me.getIERange();
					});
			domUtils.on(iframe, 'activate', function() {
						try {
							if (!_getIERange(me) && me._bakIERange) {
								me._bakIERange.select();
							}
						} catch (ex) {
						}
						me._bakIERange = null;
					});
		}
		iframe = doc = null;
	}

	Selection.prototype = {
		/**
		 * 获取原生seleciton对象
		 * 
		 * @public
		 * @function
		 * @name baidu.editor.dom.Selection.getNative
		 * @return {Selection} 获得selection对象
		 */
		getNative : function() {
			if (!this.document) {
				return null;
			}
			if (ie) {
				return this.document.selection;
			} else {
				return domUtils.getWindow(this.document).getSelection();
			}
		},

		/**
		 * 获得ieRange
		 * 
		 * @public
		 * @function
		 * @name baidu.editor.dom.Selection.getIERange
		 * @return {ieRange} 返回ie原生的Range
		 */
		getIERange : function() {

			var ieRange = _getIERange(this);
			if (!ieRange) {
				if (this._bakIERange) {
					return this._bakIERange;
				}
			}
			return ieRange;
		},

		/**
		 * 缓存当前选区的range和选区的开始节点
		 * 
		 * @public
		 * @function
		 * @name baidu.editor.dom.Selection.cache
		 */
		cache : function() {
			this.clear();
			this._cachedRange = this.getRange();
			this._cachedStartElement = this.getStart();
		},

		/**
		 * 清空缓存
		 * 
		 * @public
		 * @function
		 * @name baidu.editor.dom.Selection.clear
		 */
		clear : function() {
			this._cachedRange = this._cachedStartElement = null;
		},

		/**
		 * 获取选区对应的Range
		 * 
		 * @public
		 * @function
		 * @name baidu.editor.dom.Selection.getRange
		 * @returns {baidu.editor.dom.Range} 得到Range对象
		 */
		getRange : function() {
			var me = this;

			function optimze(range) {
				var child = me.document.body.firstChild, collapsed = range.collapsed;
				while (child && child.firstChild) {
					range.setStart(child, 0);
					child = child.firstChild;
				}
				if (!range.startContainer) {
					range.setStart(me.document.body, 0)
				}
				if (collapsed) {
					range.collapse(true);
				}
			}
			if (me._cachedRange != null) {
				return this._cachedRange;
			}
			var range = new baidu.editor.dom.Range(me.document);

			if (ie) {
				var nativeRange = me.getIERange();
				if (nativeRange) {
					transformIERangeToRange(nativeRange, range);
				} else {
					optimze(range)
				}

			} else {
				var sel = me.getNative();
				if (sel && sel.rangeCount) {
					var firstRange = sel.getRangeAt(0);
					var lastRange = sel.getRangeAt(sel.rangeCount - 1);
					range.setStart(firstRange.startContainer,
							firstRange.startOffset).setEnd(
							lastRange.endContainer, lastRange.endOffset);
					if (range.collapsed
							&& domUtils.isBody(range.startContainer)
							&& !range.startOffset) {
						optimze(range)
					}
				} else {

					optimze(range)

				}

			}

			return range;
		},

		/**
		 * 获取开始元素，用于状态反射
		 * 
		 * @public
		 * @function
		 * @name baidu.editor.dom.Selection.getStart
		 * @return {Element} 获得开始元素
		 */
		getStart : function() {
			if (this._cachedStartElement) {
				return this._cachedStartElement;
			}
			var range = ie ? this.getIERange() : this.getRange(), tmpRange, start, tmp, parent;

			if (ie) {
				if (!range) {
					// todo 给第一个值可能会有问题
					return this.document.body.firstChild;
				}
				// control元素
				if (range.item)
					return range.item(0);

				tmpRange = range.duplicate();
				// 修正ie下<b>x</b>[xx] 闭合后 <b>x|</b>xx
				tmpRange.text.length > 0 && tmpRange.moveStart('character', 1);
				tmpRange.collapse(1);
				start = tmpRange.parentElement();

				parent = tmp = range.parentElement();
				while (tmp = tmp.parentNode) {
					if (tmp == start) {
						start = parent;
						break;
					}
				}

			} else {
				range.shrinkBoundary();
				start = range.startContainer;

				if (start.nodeType == 1 && start.hasChildNodes())
					start = start.childNodes[Math.min(start.childNodes.length
									- 1, range.startOffset)];

				if (start.nodeType == 3)
					return start.parentNode;

			}
			return start;

		},
		/**
		 * 得到选区中的文本
		 * 
		 * @public
		 * @function
		 * @name baidu.editor.dom.Selection.getText
		 * @return {String} 选区中包含的文本
		 */
		getText : function() {
			var nativeSel = this.getNative(), nativeRange;
			if (nativeSel)
				nativeRange = baidu.editor.browser.ie
						? nativeSel.createRange()
						: nativeSel.getRangeAt(0);
			else
				return '';
			return nativeRange.text || nativeRange.toString();
		}
	};

})();